﻿using Microsoft.EntityFrameworkCore;
using PersonalWebsite.Domain.Abstract.DBContext;
using PersonalWebsite.Domain.Abstract.Entities;
using PersonalWebsite.Domain.Abstract.Entities.Enum;
using PersonalWebsite.Domain.Abstract.Entities.IAbility;
using System.Linq.Expressions;

namespace PersonalWebsite.Domain.Abstract.Repositories
{
    public abstract class Repository<TEntity, TDBContext> : IRepository<TEntity>
        where TEntity : Entity
        where TDBContext : DomainDBContext
    {
        protected TDBContext DbContext { get; private set; }

        protected DbSet<TEntity> DBSet { get { return DbContext.Set<TEntity>(); } }

        public Repository(TDBContext dbContext)
        {
            DbContext = dbContext;
        }

        public TEntity Add(TEntity entity)
        {
            return DBSet.Add(entity).Entity;
        }

        public async Task<TEntity> AddAsync(TEntity entity)
        {
            return (await DBSet.AddAsync(entity)).Entity;
        }

        public IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> expression)
        {
            return DBSet.Where(expression);
        }

        public bool Delete(TEntity entity)
        {
            if (entity is ISoftDelete)
            {
                (entity as ISoftDelete).IsDeleted = IsDeletedEnum.Y;
                DbContext.Update(entity);
            }
            else
                DBSet.Remove(entity);

            return true;
        }

        public TEntity Update(TEntity entity)
        {
            return DBSet.Update(entity).Entity;
        }
    }

    public abstract class Repository<TDBContext, TEntity, TKey> :
        Repository<TEntity, TDBContext>,
        IRepository<TEntity, TKey>
        where TEntity : Entity<TKey>
        where TDBContext : DomainDBContext
    {
        protected Repository(TDBContext dbContext) : base(dbContext)
        { }

        public bool Delete(TKey id)
        {
            var entity = (TEntity)Activator.CreateInstance(typeof(TEntity));
            entity.Id = id;
            DbContext.Attach(entity);

            if (entity is ISoftDelete)
            {
                (entity as ISoftDelete).IsDeleted = IsDeletedEnum.Y;
                DbContext.Update(entity);
            }
            else
                DbContext.Remove(entity);

            return true;
        }

        public TEntity Get(TKey id)
        {
            return DBSet.FirstOrDefault(c => c.Id.Equals(id));
        }

        public async Task<TEntity> GetAsync(TKey id)
        {
            return await DBSet.FirstOrDefaultAsync(c => c.Id.Equals(id));
        }
    }
}
